package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustException;
import com.heima.constants.message.NewsAutoScanConstants;
import com.heima.constants.message.NewsUpOrDownConstants;
import com.heima.constants.message.PublishArticleConstants;
import com.heima.constants.message.WemediaConstants;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.media.dtos.WmNewsDTO;
import com.heima.model.media.pojos.WmUser;
import com.heima.model.threadlocal.WmThreadLocalUtils;
import com.heima.model.wmmedia.dtos.NewsAuthDTO;
import com.heima.model.wmmedia.dtos.WmNewsPageReqDTO;
import com.heima.model.wmmedia.pojos.WmNews;
import com.heima.model.wmmedia.pojos.WmNewsMaterial;
import com.heima.model.wmmedia.vos.WmNewsVO;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Value("${file.oss.web-site}")  //"http://hmleadnewswxd.oss-cn-beijing.aliyuncs.com"  前缀访问路径
    String webSite;

    //分页带条件查询自媒体文章列表
    @Override
    public ResponseResult listWmNews(WmNewsPageReqDTO dto) {
        //非空判断
        if (dto == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //检查分页
        dto.checkParam();
        //创建Wrapper
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.lambdaQuery();
        //判断是否有文章标题
        if (dto.getKeyword() != null && dto.getKeyword().trim() != "") {
            //根据文章标题模糊查询
            wrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //判断是否有频道信息
        if (dto.getChannelId() != null) {
            //根据频道ID查询
            wrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //判断是否有文章状态
        if (dto.getStatus() != null) {
            wrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //判断是否有开始时间
        if (dto.getBeginPubDate() != null) {
            //按照推送时间查询
            wrapper.ge(WmNews::getPublishTime, dto.getBeginPubDate());
        }
        //判断是否有结束时间
        if (dto.getEndPubDate() != null) {
            wrapper.le(WmNews::getPublishTime, dto.getEndPubDate());
        }
        //获取当前用户,根据登录用户ID查询
        WmUser user = WmThreadLocalUtils.getUser();
        //非空判断
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        wrapper.eq(WmNews::getUserId, user.getId());
        //根据创建时间降序
        wrapper.orderByDesc(WmNews::getCreatedTime);
        //创建分页对象
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        //查询
        IPage<WmNews> wmNewsIPage = wmNewsMapper.selectPage(page, wrapper);
        //判断
        if (wmNewsIPage.getRecords().size() == 0) {
            //无数据,提示错误
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "未查询到文章!");
        }
        //遍历结果集合,设置回显封面图
        for (WmNews record : wmNewsIPage.getRecords()) {
            record.getImages().split("");
        }
        //有数据,封装数据返回
        PageResponseResult pageResponseResult = new PageResponseResult(dto.getPage(), dto.getSize(), wmNewsIPage.getTotal(), wmNewsIPage.getRecords());
        pageResponseResult.setHost(webSite);
        return pageResponseResult;
    }

    //保存或修改文章
    @Override
    @GlobalTransactional(rollbackFor = Exception.class, timeoutMills = 100000)
    public ResponseResult submitNews(WmNewsDTO dto) {
        //非空判断
        if (dto == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //判断当前用户是否登陆
        WmUser user = WmThreadLocalUtils.getUser();
        if (user.getId() == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //创建WmNews
        WmNews wmNews = new WmNews();
        //将dto属性复制
        BeanUtils.copyProperties(dto, wmNews);
        //设置wumNews
        wmNews.setUserId(user.getId());
        wmNews.setEnable(WemediaConstants.WM_NEWS_UP);  //1
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        //根据文章id查询数据库,判断是否存在该文章
        //判断status:文章素材布局  //-1
        if (wmNews.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }
        //获取images属性
        List<String> imagesList = dto.getImages();
        if (imagesList.size() > 0) {
            //有封面图,解析images
            String imagesStr = parseMaterial(imagesList);
            //设置到wmNews
            wmNews.setImages(imagesStr);
        }
        //判断文章类型是新增还是修改
        if (wmNews.getId() == null) {
            //新增,直接插入数据
            wmNewsMapper.insert(wmNews);
        } else {
            //修改,删除文章id和素材的关联
            LambdaQueryWrapper<WmNewsMaterial> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(WmNewsMaterial::getNewsId, wmNews.getId());
            //删除文章id和素材的关联
            wmNewsMaterialMapper.delete(wrapper);
            //修改数据
            wmNewsMapper.updateById(wmNews);
        }
        //判断文章是否是草稿
        if (dto.getStatus().equals(WemediaConstants.WM_NEWS_DRAFT_STATUS)) {
            //是草稿,不需要执行后续操作,直接返回前端
            return ResponseResult.okResult();
        }
        //不是草稿,需要创建文章id和素材的关联
        //获取文章内容
        String content = dto.getContent();
        //解析文章内容,获取文章内容中的素材url
        List<String> newMaterialUrls = parseContent(content);
        //非空判断
        if (newMaterialUrls.size() > 0) {
            //保存文章id和素材url的联系到数据库
            saveMaterialNews(wmNews.getId(), newMaterialUrls, WemediaConstants.WM_CONTENT_REFERENCE);
        }
        //保存文章id和封面url的联系到数据库
        saveMaterialNewsCover(wmNews, dto, newMaterialUrls);
        //向rabbitMQ发送待审核消息  //routingKey:wm.news.auto.scan.queue
        rabbitTemplate.convertAndSend(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE, wmNews.getId());
        //响应给前端
        return ResponseResult.okResult();
    }

    //根据id查询文章
    @Override
    public ResponseResult findWmNewsById(Integer id) {
        //非空判断
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "不存在该文章!");
        }
        return ResponseResult.okResult(wmNews);
    }

    //根据id删除自媒体文章
    @Override
    public ResponseResult deleteNews(Integer id) {
        //非空判断
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "不存在该文章!");
        }
        //查询文章状态
        if (wmNews.getStatus() == 9 && wmNews.getEnable() != 0) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "已经发布且上架的文章不能删除!");
        }
        //根据文章id查询素材
        LambdaQueryWrapper<WmNewsMaterial> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(WmNewsMaterial::getNewsId, id);
        //将符合条件的文章素材关系表的数据删除
        wmNewsMaterialMapper.delete(wrapper);
        wmNewsMapper.deleteById(id);
        //响应结果
        return ResponseResult.okResult();
    }

    //自媒体文章-上架、下架
    @Override
    public ResponseResult downOrUp(WmNewsDTO dto) {
        //非空判断
        if (dto == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id查询文章
        WmNews wmNews = wmNewsMapper.selectById(dto.getId());
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "不存在该文章!");
        }
        //判断文章状态
        if (wmNews.getStatus() != 9) {
            CustException.cust(AppHttpCodeEnum.NO_OPERATOR_AUTH, "当前文章未发布,无法进行上架或下架操作!");
        }
        //上/下架操作
        wmNews.setEnable(dto.getEnable());
        wmNewsMapper.updateById(wmNews);
        //根据上下架情况,发送MQ消息,通知修改文章配置表 以及ES库的添加删除文章
        if (dto.getEnable() == 1) {
            //上架
            rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_OR_DOWN_EXCHANGE, NewsUpOrDownConstants.NEWS_UP_ROUTE_KEY, wmNews.getArticleId());
        } else {
            //下架
            rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_OR_DOWN_EXCHANGE, NewsUpOrDownConstants.NEWS_DOWN_ROUTE_KEY, wmNews.getArticleId());
        }
        //响应前端
        return ResponseResult.okResult();
    }

    //分页查询文章和作者列表
    @Override
    public ResponseResult findList(NewsAuthDTO dto) {
        //非空判断
        if (dto == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //检查分页
        dto.checkParam();
        //保留当前页
        Integer currentPage = dto.getPage();
        //设置分页参数
        Integer size = dto.getSize();
        Integer page = (currentPage - 1) * size;
        dto.setPage(page);
        dto.setSize(size);
        String title = null;
        if (dto.getTitle() != null && dto.getTitle().trim().equals("")) {
            title = "%" + dto.getTitle() + "%";
            dto.setTitle(title);
        }
        //分页查询文章列表和作者
        List<WmNewsVO> wmNewsVOS = wmNewsMapper.findList(dto);
        //非空判断
        if (wmNewsVOS == null || wmNewsVOS.size() == 0) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "未查询到文章!");
        }
        //查询总条数
        Integer count = wmNewsMapper.count(dto);
        //封装到分页结果
        PageResponseResult pageResponseResult = new PageResponseResult();
        pageResponseResult.setCurrentPage(currentPage);
        pageResponseResult.setSize(size);
        pageResponseResult.setTotal(count.longValue());
        pageResponseResult.setData(wmNewsVOS);
        pageResponseResult.setHost(webSite);
        return pageResponseResult;
    }

    //根据文章id查询文章和作者详情
    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        //非空判断
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据文章id查询文章和作者详情
        WmNewsVO wmNewsVO = wmNewsMapper.findWmNewsVo(id);
        //非空判断
        if (wmNewsVO == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "未查询到该文章!");
        }
        ResponseResult result = ResponseResult.okResult(wmNewsVO);
        result.setHost(webSite);
        return result;
    }

    //文章状态修改方法
    public ResponseResult updateWmNewsStatus(NewsAuthDTO dto, short status) {
        //非空判断
        if (dto == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据文章id查找文章
        WmNews wmNews = wmNewsMapper.selectById(dto.getId());
        //非空判断
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "未查询到该文章!");
        }
        //判断文章状态
        if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "文章已发布");
        }
        //修改文章状态
        wmNews.setStatus(status);
        //判断传入的状态值
        if (status == WemediaConstants.WM_NEWS_AUTH_FAIL) {  //审核失败
            wmNews.setReason(dto.getMsg());  //将审核失败的消息放入
            //将修改插入数据库
            wmNewsMapper.updateById(wmNews);
        } else if (status == WemediaConstants.WM_NEWS_AUTH_PASS || status == WemediaConstants.WM_NEWS_AUTHED_STATUS) {  //审核通过
            //将修改插入数据库
            wmNewsMapper.updateById(wmNews);
            //获取发送时间
            long publishTime = wmNews.getPublishTime().getTime();
            long nowTime = new Date().getTime();
            long delayTime = publishTime - nowTime;
            //判断发布时间,发送mq延时消息,发布文章
            rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE
                    , PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY
                    , wmNews.getId(), new MessagePostProcessor() {
                        @Override
                        public Message postProcessMessage(Message message) throws AmqpException {
                            message.getMessageProperties().setHeader("x-delay", delayTime <= 0 ? 0 : delayTime);
                            return message;
                        }
                    }
            );
        }
        return ResponseResult.okResult();
    }

    //素材url集合解析成字符串方法
    public String parseMaterial(List<String> materials) {
        String materialsStr = materials.stream().map((material) -> {
            return material.replace(webSite, "").replace(" ", "");
        }).collect(Collectors.joining(","));
        return materialsStr;
    }

    //解析文章内容,获取素材url的方法
    public List<String> parseContent(String content) {
        //使用JSON工具解析字符串,将结果放入Map并放入List集合中
        List<Map> maps = JSON.parseArray(content, Map.class);
        //遍历并过滤集合
        List<String> newMaterialUrls = maps.stream().filter((map) -> {
            return map.get("type").equals("image");
        }).map((map) -> {
            return map.get("value").toString().replace(webSite, "").replace(" ", "");
        }).collect(Collectors.toList());
        return newMaterialUrls;
    }

    //保存文章id和素材url的联系到数据库
    public void saveMaterialNews(Integer newsId, List<String> newMaterialUrls, short type) {
        //根据文章id和素材url查询素材库,判断是否有对应的素材
        List<Integer> ids = wmMaterialMapper.selectRelationsIds(newMaterialUrls,
                WmThreadLocalUtils.getUser().getId());
        //判断id
        if (ids == null || ids.size() < newMaterialUrls.size()) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "相关素材缺失,文章保存失败!");
        }
        //根据newsId查询文章素材关系库,判断是否存在相同关系,存在则去除该图片链接
        LambdaQueryWrapper<WmNewsMaterial> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(WmNewsMaterial::getNewsId, newsId);
        List<WmNewsMaterial> wmNewsMaterials = wmNewsMaterialMapper.selectList(wrapper);
        if (wmNewsMaterials.size() != 0) {
            //数据库存在文章和数据的关联关系,遍历文章素材关联集合
//            List<Integer> newMaterialIds = null;

            List<Integer> newMaterialIds = ids.stream().filter(id -> {
                boolean flag = true;
                for (WmNewsMaterial wmNewsMaterial : wmNewsMaterials) {
                    if (id.equals(wmNewsMaterial.getMaterialId())) {
                        flag = false;
                    }
                }
                return flag;
            }).collect(Collectors.toList());

//            for (Integer id : ids) {
//                newMaterialIds = wmNewsMaterials.stream().filter(wmNewsMaterial -> {
//                    return !wmNewsMaterial.getMaterialId().equals(id);
//                }).map(wmNewsMaterial -> {
//                    return wmNewsMaterial.getMaterialId();
//                }).filter(id3 -> {
//                    return id3 != null && !id3.toString().trim().equals("");
//                }).
//                        collect(Collectors.toList());
//            }

            if (newMaterialIds != null && newMaterialIds.size() > 0) {
                //保存素材  传入素材id 文章id 引用类型:WemediaConstants.WM_CONTENT_REFERENCE
                wmNewsMaterialMapper.saveRelations(newMaterialIds, newsId, type);
            }
        } else {
            //数据库没有关联关系
            //保存素材  传入素材id 文章id 引用类型:WemediaConstants.WM_CONTENT_REFERENCE
            wmNewsMaterialMapper.saveRelations(ids, newsId, type);
        }
    }

    //保存文章id和封面url的联系到数据库
    public void saveMaterialNewsCover(WmNews wmNews, WmNewsDTO dto, List<String> newMaterialUrls) {
        //获取images
        List<String> images = dto.getImages();
        if (images.size() == 0) {  //没有上传封面图
            //判断文章布局
            if (wmNews.getType() == null) {  //没有上传封面图,且布局为自动,根据文章内容设置布局
                //前面对于自动布局,type设置为Null了
                if (newMaterialUrls.size() > 0 && newMaterialUrls.size() < 3) {
                    //封面使用1张图
                    images = newMaterialUrls.stream().limit(1).collect(Collectors.toList());
                    wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                } else if (newMaterialUrls.size() > 2) {
                    //封面使用多张图
                    images = newMaterialUrls.stream().limit(3).collect(Collectors.toList());
                    wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                } else {
                    //布局为自动,且封面和内容中都没有图片,设置为无图类型
                    wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
                }
            }
            //操作完成后,再次判断,没有上传封面图,且布局为无图
            if (images.size() > 0) {
                //解析images
                String imagesStr = parseMaterial(images);
                wmNews.setImages(imagesStr);
                images = images.stream().map(x -> x.replace(webSite, "")
                        .replace(" ", "")).collect(Collectors.toList());
                //保存文章id和素材url的联系到数据库
                saveMaterialNews(wmNews.getId(), images, WemediaConstants.WM_IMAGE_REFERENCE);
            }
        } else {
            //设置了封面,解析封面,保存文章id和素材url的联系到数据库
            images = images.stream().map(x -> x.replace(webSite, "")
                    .replace(" ", "")).collect(Collectors.toList());
            saveMaterialNews(wmNews.getId(), images, WemediaConstants.WM_IMAGE_REFERENCE);
        }
        //修改到数据库
        wmNewsMapper.updateById(wmNews);
    }
}
